#include "HttpRequest.h"
#define HRADSIZE 12
struct HttpRequest *httpRequestInit()
{
    struct HttpRequest *httprequest = (struct HttpRequest *)malloc(sizeof(struct HttpRequest));
    httpRequestReset(httprequest);
    httprequest->requestHeaders = (struct RequestHeader *)malloc(sizeof(struct RequestHeader) * HRADSIZE);
    return httprequest;
}

void httpRequestReset(struct HttpRequest *httpRequest)
{
    httpRequest->curState = ParseReqLine;
    httpRequest->method = NULL;
    httpRequest->url = NULL;
    httpRequest->version = NULL;
    httpRequest->requestHeadersNum = 0;
}

void httpRequestResetEx(struct HttpRequest *httpRequest)
{
    free(httpRequest->method);
    free(httpRequest->url);
    free(httpRequest->version);
    if (httpRequest->requestHeaders != NULL)
    {
        for (int i = 0; i < httpRequest->requestHeadersNum; i++)
        {
            free(httpRequest->requestHeaders[i].key);
            free(httpRequest->requestHeaders[i].value);
        }
        free(httpRequest->requestHeaders);
    }
    httpRequestReset(httpRequest);
}

void httpRequusetDestory(struct HttpRequest *httpRequest)
{
    if (httpRequest != NULL)
    {
        httpRequestResetEx(httpRequest);
        free(httpRequest);
    }
}

enum HttpRequestStates getHttpRequestStates(struct HttpRequest *httpRequest)
{
    return httpRequest->curState;
}

void httpRequestAddHeader(struct HttpRequest *httpRequest, const char *key, const char *value)
{
    httpRequest->requestHeaders[httpRequest->requestHeadersNum].key = (char *)key;
    httpRequest->requestHeaders[httpRequest->requestHeadersNum].value = (char *)value;
    httpRequest->requestHeadersNum++;
}

// 这里需要理解一下，我们希望在这个函数内部帮我们开辟空间，并将参数赋值
// 我们定义线程的时候 ，我们先定义一个 pthread_t tid 然后传入的参数是&tid  经过pthread——create之后就会得到 tid了
//
char *httpRequestGetHeader(struct HttpRequest *httpRequest, const char *key)
{
    if (httpRequest != NULL)
    {
        for (int i = 0; i < httpRequest->requestHeadersNum; i++)
        {
            if (strncasecmp(httpRequest->requestHeaders[i].key, key, strlen(key)) == 0)
            {
                return httpRequest->requestHeaders[i].value;
            }
        }
    }

    return NULL;
}

/// @brief TODO 不一定改对了
/// @param start
/// @param end
/// @param sub
/// @param ptr
/// @return
char *splitRequestLine(const char *start, const char *end, const char *sub, char **ptr)
{
    // const char* space = end;
    // if (sub != NULL)
    // {
    //     space = memmem(start, end - start, sub, strlen(sub));
    //     assert(space != NULL);
    // }
    // int length = space - start;
    // char* tmp = (char*)malloc(sizeof(char) * (length + 1));
    // strncpy(tmp, start, length);
    // tmp[length] = '\0';
    // *ptr = tmp;
    // return (char*)space + 1;

    const char *space = end;
    if (sub != NULL)
    {
        space = memmem(start, end - start, sub, strlen(sub));
        if (space == NULL)
        {
            return NULL; // 如果找不到子字符串，返回 NULL
        }
    }
    int length = space - start;
    char *tmp = (char *)malloc((length + 1) * sizeof(char));
    if (tmp == NULL)
    {
        return NULL; // 检查 malloc 成功
    }
    strncpy(tmp, start, length);
    tmp[length] = '\0';
    *ptr = tmp;
    return (char *)space + 1;
}
bool parseHttpRequestLine(struct HttpRequest *request, struct Buffer *readBuf)
{
    char *end = bufferFindCRLF(readBuf);
    if (end == NULL)
    {
        return false; // 如果找不到 \r\n，返回 false
    }
    char* start = readBuf->data + readBuf->readpos;
    int lineSize = end - start;
    printf("Initial start address: %p, end address: %p\n", (void*)start, (void*)end);
    if (lineSize)
    {
        start = splitRequestLine(start, end, " ", &request->method);
        start = splitRequestLine(start, end, " ", &request->url);
        splitRequestLine(start, end, NULL, &request->version);

#if 0
        // get /xxx/xx.txt http/1.1
        // 请求方式
        char* space = memmem(start, lineSize, " ", 1);
        assert(space != NULL);
        int methodSize = space - start;
        request->method = (char*)malloc(methodSize + 1);
        strncpy(request->method, start, methodSize);
        request->method[methodSize] = '\0';

        // 请求的静态资源
        start = space + 1;
        char* space = memmem(start, end-start, " ", 1);
        assert(space != NULL);
        int urlSize = space - start;
        request->url = (char*)malloc(urlSize + 1);
        strncpy(request->url, start, urlSize);
        request->method[urlSize] = '\0';

        // http 版本
        start = space + 1;
        //char* space = memmem(start, end - start, " ", 1);
        //assert(space != NULL);
        //int urlSize = space - start;
        request->version = (char*)malloc(end - start + 1);
        strncpy(request->url, start, end - start);
        request->method[end - start] = '\0';
#endif

        // 为解析请求头做准备
        readBuf->readpos += lineSize;
        readBuf->readpos += 2;
        // 修改状态
        request->curState = ParesReqHeaders;
        return true;
    }
    return false;
}

// 该函数处理请求行的一行
bool parseHttpRequestHeader(struct HttpRequest *request, struct Buffer *readBuf)
{
    // Debug("parseHttpRequestHeader start");
    char *end = bufferFindCRLF(readBuf);
    if (end != NULL)
    {
        char *start = readBuf->data + readBuf->readpos;
        int lineSize = end - start;
        // Debug("linesize %d",lineSize);
        // 基于: 搜索字符串
        char *middle = memmem(start, lineSize, ": ", 2);
        if (middle != NULL)
        {
            char *key = (char *)malloc(middle - start + 1);
            strncpy(key, start, middle - start);
            key[middle - start] = '\0';

            char *value = (char *)malloc(end - middle - 2 + 1);
            strncpy(value, middle + 2, end - middle - 2);
            value[end - middle - 2] = '\0';

            // 自己实现好的，往这个数组去添加一行数据
            httpRequestAddHeader(request, key, value);
            // 移动读数据的位置
            readBuf->readpos += lineSize;
            readBuf->readpos += 2;
        }
        else
        {
            // 请求头被解析完了, 跳过空行
            readBuf->readpos += 2;
            // 修改解析状态
            // 忽略 post 请求, 按照 get 请求处理
            request->curState = ParseReqDone;
        }
        // Debug("parseHttpRequestHeader end");
        return true;
    }
    return false;
}

bool parseHttpRequest(struct HttpRequest *httpRequest, struct Buffer *readBuffer, struct HttpResponse *httpResponse, struct Buffer *sendBuffer, int socket)
{
    Debug("准备开始解析http请求 ");
    Debug("消息是%s", readBuffer->data + readBuffer->readpos);
    bool flag = true;
    while (httpRequest->curState != ParseReqDone)
    {
        switch (httpRequest->curState)
        {
        case ParseReqLine:
            flag = parseHttpRequestLine(httpRequest, readBuffer);
            break;
        case ParesReqHeaders:
            flag = parseHttpRequestHeader(httpRequest, readBuffer);
            break;
        case ParseReqBody:
            // post请求才处理
            break;
        default:
            break;
        }
        if (!flag)
        {
            return flag;
        }
        // 判断是否解析完
        if (httpRequest->curState == ParseReqDone)
        {
            // 根据解析出来的原始数据，对客户端进行处理
            processHttpRequest(httpRequest, httpResponse);
            // 组织响应数据并发送给客户端
            httpResponsePrepareMsg(httpResponse, sendBuffer, socket);
        }
    }
    httpRequest->curState = ParseReqLine; // 请求解析完成之后，需要去重置状态
    return flag;
}

// 处理基于http 的get请求的方法
bool processHttpRequest(struct HttpRequest *httpRequest, struct HttpResponse *httpResponse)
{
    if (strcasecmp(httpRequest->method, "get") != 0)
    {
        return -1;
    }
    // 处理路径有中文
    decodeMsg(httpRequest->url, httpRequest->url);
    // Debug("%s ",httpRequest->method);
    // Debug("%s ",httpRequest->url);
    // 处理客户端请求的静态资源(目录或者文件)
    char *file = NULL;
    if (strcmp(httpRequest->url, "/") == 0)
    {
        file = "./";
    }
    else
    {
        file = httpRequest->url + 1;
    }
    // 获取文件属性
    Debug("file %s", file);
    struct stat st;
    int ret = stat(file, &st);
    // Debug("%d ",ret);
    if (ret == -1)
    {
        // 文件不存在 -- 回复404
        // sendHeadMsg(cfd, 404, "Not Found", getFileType(".html"), -1);
        // sendFile("404.html", cfd);
        strcpy(httpResponse->filename, "404.html");
        httpResponse->httpStatusCode = NotFound;
        strcpy(httpResponse->statusMsg, "Not Found");
        // 响应头
        addResponseHeader(httpResponse, "Content-type", getFileType(".html"));
        httpResponse->sendDataFunc = sendFile;
        return 0;
    }

    strcpy(httpResponse->filename, file);
    // Debug("我要返回的路径是 %s",httpResponse->filename); ./
    httpResponse->httpStatusCode = OK;
    strcpy(httpResponse->statusMsg, "OK");
    // Debug("我要返回消息 %s",httpResponse->statusMsg); OK
    // 判断文件类型
    if (S_ISDIR(st.st_mode))
    {
        Debug("这是一个文件夹");
        // 把这个目录中的内容发送给客户端
        // sendHeadMsg(cfd, 200, "OK", getFileType(".html"), -1);
        // sendDir(file, cfd);
        // 响应头
        addResponseHeader(httpResponse, "Content-type", getFileType(".html"));
        httpResponse->sendDataFunc = sendDir;
    }
    else
    {
        Debug("这是一个文件");
        // 把文件的内容发送给客户端
        // sendHeadMsg(cfd, 200, "OK", getFileType(file), st.st_size);
        // sendFile(file, cfd);
        // 响应头
        char tmp[12] = {0};
        sprintf(tmp, "%ld", st.st_size);
        addResponseHeader(httpResponse, "Content-type", getFileType(file));
        addResponseHeader(httpResponse, "Content-length", tmp);
        httpResponse->sendDataFunc = sendFile;
    }

    return false;
}

// 将字符转换为整形数
int hexToDec(char c)
{
    if (c >= '0' && c <= '9')
        return c - '0';
    if (c >= 'a' && c <= 'f')
        return c - 'a' + 10;
    if (c >= 'A' && c <= 'F')
        return c - 'A' + 10;
    return 0;
}

void decodeMsg(char *to, char *from)
{
    for (; *from != '\0'; ++to, ++from)
    {
        if (from[0] == '%' && isxdigit(from[1]) && isxdigit(from[2]))
        {
            // 使用 hexToDec 将两个十六进制字符转换为整数
            *to = hexToDec(from[1]) * 16 + hexToDec(from[2]);
            from += 2; // 跳过这两个十六进制字符
        }
        else
        {
            *to = *from; // 复制普通字符
        }
    }
    *to = '\0'; // 添加字符串终止符
}

const char *getFileType(const char *name)
{
    // a.jpg a.mp4 a.html
    // 自右向左查找‘.’字符, 如不存在返回NULL
    const char *dot = strrchr(name, '.');
    if (dot == NULL)
        return "text/plain; charset=utf-8"; // 纯文本
    if (strcmp(dot, ".html") == 0 || strcmp(dot, ".htm") == 0)
        return "text/html; charset=utf-8";
    if (strcmp(dot, ".jpg") == 0 || strcmp(dot, ".jpeg") == 0)
        return "image/jpeg";
    if (strcmp(dot, ".gif") == 0)
        return "image/gif";
    if (strcmp(dot, ".png") == 0)
        return "image/png";
    if (strcmp(dot, ".css") == 0)
        return "text/css";
    if (strcmp(dot, ".au") == 0)
        return "audio/basic";
    if (strcmp(dot, ".wav") == 0)
        return "audio/wav";
    if (strcmp(dot, ".avi") == 0)
        return "video/x-msvideo";
    if (strcmp(dot, ".mov") == 0 || strcmp(dot, ".qt") == 0)
        return "video/quicktime";
    if (strcmp(dot, ".mpeg") == 0 || strcmp(dot, ".mpe") == 0)
        return "video/mpeg";
    if (strcmp(dot, ".vrml") == 0 || strcmp(dot, ".wrl") == 0)
        return "model/vrml";
    if (strcmp(dot, ".midi") == 0 || strcmp(dot, ".mid") == 0)
        return "audio/midi";
    if (strcmp(dot, ".mp3") == 0)
        return "audio/mpeg";
    if (strcmp(dot, ".ogg") == 0)
        return "application/ogg";
    if (strcmp(dot, ".pac") == 0)
        return "application/x-ns-proxy-autoconfig";

    return "text/plain; charset=utf-8";
}

// 这里放入的时候 ，如果先全部存储在这个sendbuf里面的话，如果内存装不下，怎么解决
void sendFile(const char *filename, struct Buffer *sendbuffer, int cfd)
{
    // printf("%s\n", filename);
    // 1 打开文件
    int fd = open(filename, O_RDONLY);
    assert(fd > 0);
#if 1
    // 通过不停的去读取文件
    while (1)
    {
        char buf[1024];
        int len = read(fd, buf, sizeof buf);
        if (len > 0)
        {
            // int ret = send(cfd, buf, len, 0);
            bufferAppendData(sendbuffer, buf, len);
            // 这里优化一下，读到数据久发送

            // if (errno == EPIPE || errno == ECONNRESET)
            // {
            //     printf("send error: %s\n", strerror(errno));
            //     close(cfd);
            //     break;
            // }
#ifndef MSG_SEND_AUTO // 这是ifndef 表示没有定义这个宏，这个代码是有效的 定义了就是无效的
            bufferSendData(sendbuffer, cfd);
#endif
        }
        else if (len == 0)
        {
            break;
        }
        else
        {
            // 读文件失败了，也要关掉
            close(fd);
            perror("read");
        }
    }
#else
    off_t offset = 0;

    struct stat file_stat;
    if (fstat(fd, &file_stat) == -1)
    {
        perror("Could not get file size");
        close(fd);
        return -1;
    }
    // int size = lseek(fd, 0, SEEK_END);
    // // 文件指针移动到文件头部
    // lseek(fd, 0, SEEK_SET);

    int size = file_stat.st_size;

    while (offset < size)
    {
        // 不是永远都发送size大小
        ssize_t bytes_sent = sendfile(cfd, fd, &offset, size - offset);
        // printf("ret value:%d\n", ret);
        if (bytes_sent < 0)
        {
            if (errno == EPIPE || errno == ECONNRESET)
            {
                printf("send error: %s\n", strerror(errno));
                close(cfd);
                break;
            }
            // eagin 表示没数据数据继续进行尝试
            if (errno != EAGAIN && errno != EINTR)
            {
                Debug("我执行到这一行了");
                perror("Failed to send file");
                close(fd);
                return -1;
            }
        }
    }

#endif
    close(fd);
}

void sendDir(const char *dirName, struct Buffer *sendBuf, int cfd)
{
    char buf[4096] = {0};
    sprintf(buf, "<html><head><title>%s</title></head><body><table>", dirName);
    struct dirent **namelist;
    int num = scandir(dirName, &namelist, NULL, alphasort);
    for (int i = 0; i < num; ++i)
    {
        // 取出文件名 namelist 指向的是一个指针数组 struct dirent* tmp[]
        char *name = namelist[i]->d_name;
        struct stat st;
        char subPath[1024] = {0};
        sprintf(subPath, "%s/%s", dirName, name);
        stat(subPath, &st);
        if (S_ISDIR(st.st_mode))
        {
            // a标签 <a href="">name</a>
            sprintf(buf + strlen(buf),
                    "<tr><td><a href=\"%s/\">%s</a></td><td>%ld</td></tr>", name, name, st.st_size);
        }
        else
        {
            sprintf(buf + strlen(buf),
                    "<tr><td><a href=\"%s\">%s</a></td><td>%ld</td></tr>", name, name, st.st_size);
        }
        // send(cfd, buf, strlen(buf), 0);
        bufferAppendString(sendBuf, buf);
#ifndef MSG_SEND_AUTO
        bufferSendData(sendBuf, cfd);
#endif
        memset(buf, 0, sizeof(buf));
        free(namelist[i]);
    }
    sprintf(buf, "</table></body></html>");
    // send(cfd, buf, strlen(buf), 0);
    bufferAppendString(sendBuf, buf);
#ifndef MSG_SEND_AUTO
    bufferSendData(sendBuf, cfd);
#endif
    free(namelist);
}